#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Filename: common_ui.py
# Author: ChenChangSong
# Date: 2025-08-24

"""
功能描述: 公共UI组件与日志窗体封装。

- 日志显示模块: 单例 TextEditLogger，可被各功能模块复用。
- 工具按钮: 清空历史日志、帮助文档、联系我、版本信息。

注意: 仅实现 UI 与日志写入能力，业务函数在各功能页中调用。
"""
import sys
import logging
import webbrowser
from pathlib import Path
from typing import Optional

from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (
    QHBoxLayout,
    QLabel,
    QDialog,
    QDialogButtonBox,
    QFormLayout,
    QPushButton,
    QTextEdit,
    QVBoxLayout,
    QWidget,
)


HELP_DOC_URL = (
    "https://dcnh9obfpxxh.feishu.cn/docx/D8PydWAcBoLlblxsAlZcLbYCnsd?from=from_copylink"
)


import re
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QTextCursor, QTextCharFormat, QFont

class TextEditLogger(logging.Handler):
    """将日志写入到 QTextEdit 的 Handler，支持URL链接点击。"""

    def __init__(self, target_text_edit: QTextEdit) -> None:
        super().__init__()
        self.target_text_edit = target_text_edit
        self.setLevel(logging.INFO)
        # 设置QTextEdit支持富文本
        self.target_text_edit.setAcceptRichText(True)
        # 保存原始的鼠标事件处理方法
        self.original_mouse_press = self.target_text_edit.mousePressEvent
        # 替换鼠标按下事件处理
        self.target_text_edit.mousePressEvent = self._handle_mouse_press
        # 设置鼠标指针在URL上时的样式
        self.target_text_edit.viewport().setMouseTracking(True)
        self.target_text_edit.mouseMoveEvent = self._handle_mouse_move

    def _handle_mouse_move(self, event):
        """处理鼠标移动事件，当鼠标悬停在URL上时改变光标样式。"""
        # 获取鼠标位置的文本
        cursor = self.target_text_edit.cursorForPosition(event.pos())
        # 检查光标位置前后的文本，找到完整的URL
        full_text = self.target_text_edit.toPlainText()
        position = cursor.position()
        
        # 查找URL的起始和结束位置
        url_pattern = r'(https?://[\w\-._~:/?#[\]@!$&\'()*+,;=.]+)'
        is_on_url = False
        
        for match in re.finditer(url_pattern, full_text):
            if match.start() <= position <= match.end():
                is_on_url = True
                break
        
        # 根据是否在URL上设置鼠标指针样式
        if is_on_url:
            self.target_text_edit.setCursor(Qt.PointingHandCursor)
        else:
            self.target_text_edit.setCursor(Qt.IBeamCursor)
        
        # 调用原始的鼠标移动事件处理
        QTextEdit.mouseMoveEvent(self.target_text_edit, event)

    def _handle_mouse_press(self, event):
        """处理鼠标按下事件，当Ctrl+左键点击时打开URL。"""
        # 检查是否是Ctrl+左键点击
        if event.modifiers() == Qt.ControlModifier and event.button() == Qt.LeftButton:
            # 获取鼠标位置的文本
            cursor = self.target_text_edit.cursorForPosition(event.pos())
            # 检查光标位置前后的文本，找到完整的URL
            full_text = self.target_text_edit.toPlainText()
            position = cursor.position()
            
            # 查找URL的起始和结束位置
            url_pattern = r'(https?://[\w\-._~:/?#[\]@!$&\'()*+,;=.]+)'
            
            for match in re.finditer(url_pattern, full_text):
                if match.start() <= position <= match.end():
                    # 找到包含当前位置的URL
                    url = match.group(1)
                    # 打开链接
                    webbrowser.open(url)
                    return
        
        # 如果不是Ctrl+左键点击链接，则调用原始的鼠标事件处理
        self.original_mouse_press(event)

    def emit(self, record: logging.LogRecord) -> None:
        try:
            # 只显示comm_log记录器的日志到界面
            if record.name == 'comm_log':
                msg = self.format(record)
                # 识别URL链接
                url_pattern = r'(https?://[\w\-._~:/?#[\]@!$&\'()*+,;=.]+)'
                
                # 先将文本添加到QTextEdit
                self.target_text_edit.append(msg)
                
                # 找到并突出显示URL
                cursor = self.target_text_edit.textCursor()
                # 移动到刚添加的行
                cursor.movePosition(QTextCursor.End)
                cursor.movePosition(QTextCursor.StartOfLine)
                line_text = cursor.block().text()
                
                # 查找URL并设置格式
                for match in re.finditer(url_pattern, line_text):
                    # 创建链接样式
                    link_format = QTextCharFormat()
                    link_format.setForeground(QColor('#4a9eff'))  # 蓝色
                    link_format.setFontUnderline(True)  # 下划线
                    
                    # 应用格式到URL
                    cursor.setPosition(cursor.block().position() + match.start())
                    cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, len(match.group(1)))
                    cursor.setCharFormat(link_format)
                
                # 自动滚动到底部
                self.target_text_edit.verticalScrollBar().setValue(
                    self.target_text_edit.verticalScrollBar().maximum())
        except Exception as e:  # pragma: no cover - 防御性
            # 记录错误但不中断程序
            print(f"日志处理错误: {str(e)}")
            # 简单回退
            self.target_text_edit.append(msg)


# 全局日志面板实例
_log_panel = None

# 模块级别的日志函数

def show_info_message(message: str) -> None:
    """模块级别的信息日志函数（只保存到文件，不显示在界面）"""
    logging.info(message)


def show_error_message(message: str) -> None:
    """模块级别的错误日志函数（只保存到文件，不显示在界面）"""
    logging.error(message)


def log_to_ui_info(message: str) -> None:
    """模块级别的界面信息日志函数（只显示在界面，不保存到文件）"""
    import logging
    comm_logger = logging.getLogger('comm_log')
    comm_logger.info(message)


def log_to_ui_error(message: str) -> None:
    """模块级别的界面错误日志函数（只显示在界面，不保存到文件）"""
    import logging
    comm_logger = logging.getLogger('comm_log')
    comm_logger.error(message)


def clear_screen_logs() -> None:
    """清空界面日志（只清空界面，不清空历史日志文件）"""
    if _log_panel:
        _log_panel.clear_screen_logs()


class LogPanel(QWidget):
    """带工具区的日志面板。"""
    
    def __init__(self, version_text: str = "[v3.1]") -> None:# 版本号
        super().__init__()
        self.version_text = version_text
        self._init_ui()
        # 设置全局日志面板实例
        global _log_panel
        _log_panel = self

    def _init_ui(self) -> None:
        layout = QVBoxLayout(self)

        title = QLabel("日志信息:")
        layout.addWidget(title)

        self.log_text_edit = QTextEdit()
        self.log_text_edit.setReadOnly(True)
        self.log_text_edit.setStyleSheet(
            "QTextEdit{background:#0b0c10;color:#c5c6c7;font-family:Consolas;}"  # 微美化
        )
        layout.addWidget(self.log_text_edit, 1)

        tools_layout = QHBoxLayout()

        self.btn_clear_screen = QPushButton("[清空日志信息]")
        self.btn_clear_screen.clicked.connect(self.clear_screen_logs)
        tools_layout.addWidget(self.btn_clear_screen)
        
        self.btn_clear = QPushButton("[清空历史日志文件]")
        self.btn_clear.clicked.connect(self.clear_logs)
        tools_layout.addWidget(self.btn_clear)

        self.btn_help = QPushButton("[帮助文档]")
        self.btn_help.clicked.connect(lambda: webbrowser.open(HELP_DOC_URL))
        tools_layout.addWidget(self.btn_help)

        self.btn_contact = QPushButton("[联系我]")
        self.btn_contact.clicked.connect(self._contact)
        tools_layout.addWidget(self.btn_contact)

        self.btn_version = QLabel(self.version_text)
        self.btn_version.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        self.btn_version.setStyleSheet("color:#666;")
        tools_layout.addWidget(self.btn_version)

        tools_layout.addStretch(1)
        layout.addLayout(tools_layout)

        # 绑定 logging
        self._logger_handler = TextEditLogger(self.log_text_edit)
        formatter = logging.Formatter("[%(asctime)s] %(levelname)s - %(message)s")
        self._logger_handler.setFormatter(formatter)
        # 将日志处理器附加到根日志记录器
        self.attach_comm_logger()

    def attach_comm_logger(self) -> None:
        """将日志处理器附加到comm_log记录器"""
        import logging
        logger = logging.getLogger('comm_log')
        if self._logger_handler not in logger.handlers:
            logger.addHandler(self._logger_handler)
        logger.setLevel(logging.INFO)

    def clear_screen_logs(self) -> None:
        """仅清空界面日志"""
        self.log_text_edit.clear()
        
    def clear_logs(self) -> None:
        """清空界面日志并清空历史日志文件（仅通过[清空历史日志文件]按钮调用）"""
        # 清空界面日志
        self.clear_screen_logs()
        # 导入并调用清空历史日志文件的函数
        try:
            from function_code.comm.clear_history_log import clear_history_log
            success, message = clear_history_log()
            # 直接将结果显示在界面上，无论日志来源
            self.append_log(message)
            # 同时记录到日志系统
            if success:
                logging.info(message)
            else:
                logging.error(message)
        except Exception as e:
            error_msg = f"调用清空历史日志文件功能失败: {str(e)}"
            self.append_log(error_msg)
            logging.error(error_msg)
    
    def append_log(self, message: str) -> None:
        """添加日志到界面显示"""
        self.log_text_edit.append(message)

    @staticmethod
    def _contact() -> None:
        """显示联系提示消息框"""
        from PyQt5.QtWidgets import QMessageBox
        QMessageBox.information(None, "联系信息", "请企微联系昌松")




def get_project_root() -> Path:
    # 获取程序运行时的目录
    if getattr(sys, 'frozen', False):
        # 当程序被打包成可执行文件时，获取可执行文件所在目录
        return Path(sys.executable).parent
    else:
        # 当程序在开发环境中运行时，获取项目根目录
        return Path(__file__).resolve().parents[1]


class ClickableLabel(QLabel):
    clicked = pyqtSignal()

    def mouseReleaseEvent(self, event):  # type: ignore[override]
        super().mouseReleaseEvent(event)
        self.clicked.emit()


class InfoWithImageDialog(QDialog):
    """图文说明弹窗，点击图片可打开系统查看大图。"""

    def __init__(self, title: str, text: str, image_path: Path) -> None:
        super().__init__()
        self.setWindowTitle(title)
        layout = QVBoxLayout(self)
        text_label = QLabel(text)
        text_label.setWordWrap(True)
        layout.addWidget(text_label)
        if image_path.exists():
            img_label = ClickableLabel()
            img_label.setAlignment(Qt.AlignCenter)
            from PyQt5.QtGui import QPixmap

            pix = QPixmap(str(image_path))
            if not pix.isNull():
                max_w = 520
                if pix.width() > max_w:
                    pix = pix.scaledToWidth(max_w, Qt.SmoothTransformation)
                img_label.setPixmap(pix)
            img_label.setToolTip("点击查看大图")
            img_label.clicked.connect(lambda: webbrowser.open(image_path.as_uri()))
            layout.addWidget(img_label)
        buttons = QDialogButtonBox(QDialogButtonBox.Ok)
        buttons.accepted.connect(self.accept)
        layout.addWidget(buttons)


def apply_global_style(app) -> None:
    """应用统一的浅色简洁主题样式。"""
    app.setStyleSheet(
        """
        QMainWindow { background: #f7f8fa; }
        QTabWidget::pane { border: 1px solid #e6e8eb; background: #ffffff; }
        QTabBar::tab { padding: 8px 18px; margin: 0 2px; border: 1px solid transparent; }
        QTabBar::tab:selected { color:#1677ff; border-bottom: 2px solid #1677ff; background:#ffffff; }
        QGroupBox { border: 1px solid #e6e8eb; border-radius: 6px; margin-top: 8px; padding: 10px; background:#ffffff; }
        QLabel { color:#2b2f36; }
        QLineEdit, QSpinBox, QTextEdit, QListWidget { 
            background:#ffffff; border:1px solid #d9d9d9; border-radius:4px; padding:6px; 
            selection-background-color:#e6f4ff; selection-color:#1f1f1f; 
        }
        QLineEdit:focus, QSpinBox:focus, QTextEdit:focus { border:1px solid #1677ff; }
        QPushButton { background:#1677ff; color:#fff; border:none; border-radius:4px; padding:6px 14px; height:28px; }
        QPushButton:hover { background:#4096ff; }
        QPushButton:disabled { background:#bfbfbf; }
        QToolButton { background:#fff; border:1px solid #d9d9d9; border-radius:50%; width:22px; height:22px; }
        QToolButton:hover { background:#f5f5f5; }
        QTextEdit { background:#0b0c10; color:#c5c6c7; border-radius:6px; }
        QDialog { background:#ffffff; }
        QDialog QPushButton { background:#1677ff; }
        QHeaderView::section { background:#fafafa; padding:4px; border:1px solid #e6e8eb; }
        """
    )


